
import java.applet.Applet;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.Box;
import java.awt.*;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import javax.media.j3d.*;
import com.sun.j3d.utils.universe.*;
import javax.vecmath.*;

/**
* @author Joshua Lawless
* Revision Date: May 10, 2010
* 
* Current version provides lower
* leg movement only. Test data only moves
* according to first input, subsequent
* rotations currently do not register.  
*/
@SuppressWarnings("serial")
public class KpodGraphics extends Applet{

	// Create a behavior trigger class
	// The behavior trigger class will 
	// awaken upon receiving data from
	// Kpodconnection (Not currently Implemented)
	public class MoveJoint extends Behavior{
		private TransformGroup targetTG;
		private WakeupCriterion dataFeed;
		
		MoveJoint(TransformGroup targetTG)
		{
			this.targetTG = targetTG;
		}
		
		public void initialize() {
			//provide wakeup
		}
		
		public void processStimulus(Enumeration arg0) {
			//provide wakeup
		}
		
	}
	// List of angle rotations
	private ArrayList<Float> testData = new ArrayList<Float>();
	private BranchGroup objRoot = new BranchGroup();
	// Tibia and hip positions
	private TransformGroup boneMove;
	private TransformGroup hipMove;
	//Defines appearance of 3d objects
	//Yellowish Gold Color
    private Appearance Appear = new Appearance();
	private Color3f woodCol = new Color3f(0.53f, 0.4f, 0.08f);
	private ColoringAttributes ca = new ColoringAttributes(woodCol, ColoringAttributes.NICEST);
	//PolygonAttributes are set to create a wire frame
	//for ease of visibility
	private PolygonAttributes pa = new PolygonAttributes();
	// The 3d objects
	private Box femur = new Box(0.025f, 0.3f, 0.05f, Appear);
	private Box tibia = new Box(0.025f, 0.3f, 0.05f, Appear);
	private Box hipBone = new Box(0.025f, 0.1f, 0.05f, Appear); //width, height, length
	 
	
/*
 * Constructor	
 */
public KpodGraphics(){
	BufferedReader inputFile = null;
	try 
	{
		inputFile = new BufferedReader(new FileReader("testdata.txt"));
	} 
	catch (FileNotFoundException e) 
	{
		System.out.println("Test File Not Found\n");
		e.printStackTrace();
	}
	try 
	{	
		while( inputFile.ready()  )
		{
			testData.add(Float.parseFloat(inputFile.readLine()));
		}
		inputFile.close();
	} 
	catch (IOException e) 
	{
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	
	setLayout(new BorderLayout());
	GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
	Canvas3D canvas3D = new Canvas3D(config);
	add("Center", canvas3D);
	BranchGroup scene = createSceneGraph();
	scene.compile();
	SimpleUniverse theWorld = new SimpleUniverse(canvas3D);
	theWorld.getViewingPlatform().setNominalViewingTransform();
	theWorld.addBranchGraph(scene);
}

/*
 * Simply executes main graphics as applet
 */
public void run(){	
	Frame frame = new MainFrame(this, 500, 500);
}

/*
 * Generate all objects and their transformations 
 * in the universe
 */
public BranchGroup createSceneGraph() {
	
	 // Color polygons' appearance
	 Appear.setColoringAttributes(ca);
	 pa.setPolygonMode(PolygonAttributes.POLYGON_LINE);
	 Appear.setPolygonAttributes(pa);
	
	 // List of total transformations
	 Transform3D rotate = new Transform3D();
	 Transform3D tempRotate = new Transform3D();
	 Transform3D translate1 = new Transform3D();
	 Transform3D translate2 = new Transform3D();
	 Transform3D ninetyDegreeRot = new Transform3D();
	 Transform3D yAxis = new Transform3D();
	 
	 // lay hipbone flat
	 ninetyDegreeRot.rotZ(Math.PI/2);
	 
	 //hip and tibia placement is unique, femur will remain at origin
	 translate1.set(new Vector3f(0.0f, -0.65f, 0.0f));
	 translate2.set(new Vector3f(-0.14f, 0.32f, 0.0f));
	 
	 boneMove = new TransformGroup(translate1);
	 hipMove = new TransformGroup(translate2);
	 TransformGroup temp = new TransformGroup();
	 boneMove.addChild(temp);
	 
	 rotate.rotX(Math.PI/4.0d);
	 tempRotate.rotY(Math.PI/5.0d);
	 rotate.mul(tempRotate);
	 
	 TransformGroup objRotate = new TransformGroup(rotate);
	 TransformGroup ninetyRot = new TransformGroup(ninetyDegreeRot);
	 TransformGroup objSpin = new TransformGroup();
	 
	 //All objects will rotate 360 degrees
	 objSpin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

	 //Generate array of rotations based on Test data
	 Transform3D testTrans[] = new Transform3D[testData.size()];
	 for(int i = 0; i < testData.size(); i++)
	 {
		testTrans[i] = new Transform3D();
		testTrans[i].rotX((float)Math.PI/2);
	 }
	 
	 Alpha[] tibAngRotAlpha = new Alpha[testData.size()]; 
	 temp.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
	 float[] floatTemp = new float[testData.size()];

	 for(int i = 0; i < testData.size(); i++)
	 {
		// filter exceptional data
		if(testData.get(i) > 10)
		{
			floatTemp[i] = 1.0f;
		}
		else
		{
			floatTemp[i] = testData.get(i); 
		}
		System.out.println(floatTemp[i]);
		tibAngRotAlpha[i] = new Alpha(-1, 5000);
	 }
	 floatTemp[0] = 0.0f;
	 floatTemp[testData.size() - 1] = 1.0f;
	 RotationInterpolator tibRotInter[] = new RotationInterpolator[testData.size()];
	 BoundingSphere[] tibBounds = new BoundingSphere[testData.size()];
	 
	 // Initialize array of rotations 
	 // Add individual rotations as
	 // children of temp node
	 for(int i = 0; i < testData.size(); i++)
	 {
		 tibBounds[i] = new BoundingSphere();
		 tibRotInter[i] = new RotationInterpolator(
			 tibAngRotAlpha[i], temp, testTrans[i], 0.0f, (float)-testData.get(i));
		 tibRotInter[i].setSchedulingBounds(tibBounds[i]);
		 temp.addChild(tibRotInter[i]);
	 }
	 // Root Graph: All objects rotate 360 degrees around universe
	 // Hip and tibia are specially placed, femur begins at origin
	 // Hip lies flat with respect to vertical femur and tibia
	 objRoot.addChild(objRotate);
	 objRotate.addChild(objSpin);
	 objSpin.addChild(hipMove);
	 objSpin.addChild(boneMove);
	 hipMove.addChild(ninetyRot);
	 temp.addChild(tibia);
	 
	 ninetyRot.addChild(hipBone);
	 objSpin.addChild(femur);

	 // Define time of behavior pattern
	 Alpha rotationAlpha = new Alpha(-1, 4000);
	 // Define rotation form
	 RotationInterpolator rotator = new RotationInterpolator(
			 	rotationAlpha, objSpin, yAxis, 0.0f, (float) Math.PI*2.0f);
	 // Define the spatial limit to which the 
	 // objects can spin in the universe
	 BoundingSphere bounds = new BoundingSphere();
	 rotator.setSchedulingBounds(bounds);
	 objSpin.addChild(rotator);
	 
	 // Compile scene graph starting from root
	 objRoot.compile();
	
	 return objRoot;
	} 

public static void main(String[] args) {
	KpodGraphics mainTest = new KpodGraphics();
	mainTest.run();
	}

}
